/*!
 * Migrated from jQuery Upload File Plugin
 * version: 4.0.10
 * Copyright (c) 2013 Ravishanker Kusuma
 * http://hayageek.com/
 */
define(["form.js"], function (form) {
    var scope = this, $ = bowlder;
    var roles, feature = {};
    scope.fileInfos = [];
    feature.fileapi = $("<input type='file'/>")[0].files !== undefined;
    feature.formdata = window.FormData !== undefined;
    var state = scope.state = $.extend({
        // These are the defaults.
        url: /dev\.f2?e|qa\.developer/.test(location.hostname) ? "/system/tools/node/upload.js.node" : "http://upload.buzz.163.com/upload/image",
        method: "POST",
        enctype: "multipart/form-data",
        returnType: "json",
        allowDuplicates: true,
        duplicateStrict: false,
        allowedTypes: "*",
        acceptFiles: "*",
        fileName: "file",
        formData: {
            uploadtype: "cms",
            bucketName: "cms-bucket",
            from: "163"
        },
        dynamicFormData: false,
        maxFileSize: -1,
        maxFileCount: -1,
        multiple: true,
        dragDrop: true,
        autoSubmit: true,
        showCancel: true,
        showAbort: true,
        showDone: false,
        showDelete: false,
        showError: true,
        showStatusAfterSuccess: true,
        showStatusAfterError: true,
        showFileCounter: true,
        fileCounterStyle: "). ",
        showFileSize: true,
        showProgress: true,
        nestedForms: true,
        showDownload: false,
        onSelect: function (files) {},
        onSubmit: function (files, xhr) {},
        sequential: false,
        sequentialCount:2,
        customProgressBar: false,
        dragDropHoverClass: "state-hover",
        multiDragErrorStr: "不允许同时拖拽多个文件。",
        extErrorStr: "无法上传。后缀名应为: ",
        duplicateErrorStr: "无法上传。该文件已存在。",
        sizeErrorStr: "无法上传。文件应小于: ",
        uploadErrorStr: "上传异常",
        maxFileCountErrorStr: "无法上传。文件数应少于:",
        customErrorKeyStr: "ajaxupload-error",
        showQueueDiv: false,
        showPreview: true,
        uploadQueueOrder:'top'
    });
    this.fileCounter = 1;
    this.selectedFiles = 0;
    var formGroup = "ajax-file-upload-" + (new Date().getTime());
    this.formGroup = formGroup;
    this.responses = [];
    this.existingFileNames = [];
    if(!feature.formdata){ //check drag drop enabled.
        state.dragDrop = false;
    }
    if(!feature.formdata || state.maxFileCount === 1) {
        state.multiple = false;
    }

	this.startUpload = function () {
	   	$("form").each(function(i,items){
	   		if($(this).hasClass(scope.formGroup)){
				mainQ.push($(this));
	   		}
	   	});

        if(mainQ.length >= 1)
	 		submitPendingUploads();
    }
    this.getFileCount = function () {
        return scope.selectedFiles;
    }
    this.stopUpload = function () {
        $("." + state.abortButtonClass).each(function (i, items) {
            if($(this).hasClass(scope.formGroup)) $(this).trigger('click');
        });
        $("." + state.cancelButtonClass).each(function (i, items) {
            if($(this).hasClass(scope.formGroup)) $(this).trigger('click');
        });
    }
    this.cancelAll = function () {
        $("." + state.cancelButtonClass).each(function (i, items) {
            if($(this).hasClass(scope.formGroup)) $(this).trigger('click');
        });
    }
    this.reset = function (removeStatusBars) {
		scope.fileCounter = 1;
		scope.selectedFiles = 0;
		state.errMsg = "";
		//remove all the status bars.
		if(removeStatusBars != false){
			roles.container.html("");
		}
    }
	this.remove = function(){
		roles.container.html('');
	}
    this.getResponses = function () {
        return this.responses;
    }
    var mainQ = [];
    var progressQ = []
    var running = false;
    function submitPendingUploads() {
		if(running) return;
		running = true;
        (function checkPendingForms() {
            //if not sequential upload all files
            if(!state.sequential) state.sequentialCount=99999;
            
			if(mainQ.length == 0 && progressQ.length == 0){
				running= false;
			}else{
				if( progressQ.length < state.sequentialCount){
					var frm = mainQ.shift();
					if(frm != undefined){
				    	progressQ.push(frm);
				    	//Remove the class group.
				    	frm.removeClass(scope.formGroup);
    	    			frm.trigger('submit');
        			}
				}						
				window.setTimeout(checkPendingForms, 100);
			}
        })();
    }
    
    function setDragDropHandlers(obj, s, ddObj) {
        ddObj.on('dragenter', function (e) {
            e.stopPropagation();
            e.preventDefault();
            $(this).addClass(s.dragDropHoverClass);
        });
        ddObj.on('dragover', function (e) {
            e.stopPropagation();
            e.preventDefault();
            var that = $(this);
            if (that.hasClass(s.dragDropContainerClass) && !that.hasClass(s.dragDropHoverClass)) {
                that.addClass(s.dragDropHoverClass);
            }
        });
        ddObj.on('drop', function (e) {
            e.preventDefault();
            $(this).removeClass(s.dragDropHoverClass);
            s.erroMsg = "";
            var files = e.originalEvent.dataTransfer.files;
            if(!s.multiple && files.length > 1) {
                s.erroMsg = s.multiDragErrorStr;
                return;
            }
            if(s.onSelect(files) === false) return;
            serializeAndUploadFiles(s, obj, files);
        });
        ddObj.on('dragleave', function (e) {
            $(this).removeClass(s.dragDropHoverClass);
        });

        $(document).on('dragenter', function (e) {
            e.stopPropagation();
            e.preventDefault();
        }).on('dragover', function (e) {
            e.stopPropagation();
            e.preventDefault();
            var that = $(e.target);
            if (!that.hasClass(s.dragDropContainerClass)) {
                that.removeClass(s.dragDropHoverClass);
            }
        }).on('drop', function (e) {
            e.stopPropagation();
            e.preventDefault();
            $(e.target).removeClass(s.dragDropHoverClass);
        });

    }

    function getSizeStr(size) {
        var sizeStr = "";
        var sizeKB = size / 1024;
        if(parseInt(sizeKB) > 1024) {
            var sizeMB = sizeKB / 1024;
            sizeStr = sizeMB.toFixed(2) + " MB";
        } else {
            sizeStr = sizeKB.toFixed(2) + " KB";
        }
        return sizeStr;
    }

    function serializeData(extraData) {
        var serialized = [];
        if($.isString(extraData)) {
            serialized = extraData.split('&');
        } else {
            serialized = $.param(extraData).split('&');
        }
        var len = serialized.length;
        var result = [];
        var i, part;
        for(i = 0; i < len; i++) {
            serialized[i] = serialized[i].replace(/\+/g, ' ');
            part = serialized[i].split('=');
            result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]);
        }
        return result;
    }
    function createFileInfo(name){
        var info = {
            filename: name
        };
        scope.fileInfos[state.uploadQueueOrder=='bottom'?"push":"unshift"](info)
        return info;
    }
    function serializeAndUploadFiles(s, obj, files) {
        for(var i = 0; i < files.length; i++) {
            if(!isFileTypeAllowed(s, files[i].name)) {
                s.errMsg = "<b>" + files[i].name + "</b> " + s.extErrorStr + s.allowedTypes;
                continue;
            }
            if(!s.allowDuplicates && isFileDuplicate(files[i].name)) {
                s.errMsg = "<b>" + files[i].name + "</b> " + s.duplicateErrorStr;
                continue;
            }
            if(s.maxFileSize != -1 && files[i].size > s.maxFileSize) {
                s.errMsg = "<b>" + files[i].name + "</b> " + s.sizeErrorStr + getSizeStr(s.maxFileSize);
                continue;
            }
            if(s.maxFileCount != -1 && scope.selectedFiles >= s.maxFileCount) {
                s.errMsg = "<b>" + files[i].name + "</b> " + s.maxFileCountErrorStr + s.maxFileCount;
                continue;
            }
            scope.selectedFiles++;
            scope.existingFileNames.push(files[i].name);
            var ts = s;
            var fd = new FormData();
            var fileName = s.fileName.replace("[]", "");
            fd.append(fileName, files[i]);
            var extraData = s.formData;
            if(extraData) {
                var sData = serializeData(extraData);
                for(var j = 0; j < sData.length; j++) {
                    if(sData[j]) {
                        fd.append(sData[j][0], sData[j][1]);
                    }
                }
            }
            ts.fileData = fd;

            var info = createFileInfo(files[i].name);
            var fileNameStr = "";
            if(s.showFileCounter) fileNameStr = scope.fileCounter + s.fileCounterStyle + files[i].name
            else fileNameStr = files[i].name;

			if(s.showFileSize)
				fileNameStr += " ("+getSizeStr(files[i].size)+")";
			
			info.filename = fileNameStr;
            var form = $("<form style='display:block; position:absolute;left: 150px;' class='" + scope.formGroup + "' method='" + s.method + "' action='" +
                         s.url + "' enctype='" + s.enctype + "' target='_blank'></form>");
            form.appendTo(document.body);
            var fileArray = [];
            fileArray.push(files[i].name);
            ajaxFormSubmit(form, ts, info, fileArray, obj, files[i]);
            scope.fileCounter++;
        }
    }

    function isFileTypeAllowed(s, fileName){
        var fileExtensions = s.allowedTypes.toLowerCase().split(/[\s,]+/g);
        var ext = fileName.split('.').pop().toLowerCase();
        if(s.allowedTypes != "*" && fileExtensions.indexOf(ext) == -1) {
            return false;
        }
        return true;
    }

    function isFileDuplicate(filename) {
        var duplicate = false;
        if (scope.existingFileNames.length) {
            for (var x=0; x<scope.existingFileNames.length; x++) {
                if (scope.existingFileNames[x] == filename
                    || state.duplicateStrict && scope.existingFileNames[x].toLowerCase() == filename.toLowerCase()
                   ) {
                       duplicate = true;
                   }
            }
        }
        return duplicate;
    }

    function removeExistingFileName(fileArr) {
        if (scope.existingFileNames.length) {
            for (var x=0; x<fileArr.length; x++) {
                var pos = scope.existingFileNames.indexOf(fileArr[x]);
                if (pos != -1) {
                    scope.existingFileNames.splice(pos, 1);
                }
            }
        }
    }

    function getSrcToPreview(file, info) {
        if(file) {
            var reader = new FileReader();
            reader.onload = function (e) {
                info.src = e.target.result;
                scope.$refresh();
            };
            reader.readAsDataURL(file);
        }
    }

    function updateFileCounter(s) {
        var len = scope.fileInfos.length;
        $.each(scope.fileInfos, function (info, i) {
            var arr = info.filename.split(s.fileCounterStyle);
            var count = s.uploadQueueOrder != 'bottom' ? len - i : i+1;
            info.filename = count + s.fileCounterStyle + arr[1];
        });
    }

    function createCustomInputFile(obj, group, s, uploadLabel) {
        var form = $("<form method='" + s.method + "' action='" + s.url + "' enctype='" + s.enctype + "'></form>");
        var fileInputStr = "<input type='file' name='" + s.fileName + "' accept='" + s.acceptFiles + "'/>";
        if(s.multiple) {
            if(s.fileName.indexOf("[]") != s.fileName.length - 2){
                s.fileName += "[]";
            }
            fileInputStr = "<input type='file' name='" + s.fileName + "' accept='" + s.acceptFiles + "' multiple/>";
        }
        var fileInput = $(fileInputStr).appendTo(form);
        fileInput.bind("change", function () {
            s.errMsg = "";
            var fileExtensions = s.allowedTypes.toLowerCase().split(",");
            var fileArray = [];
            if(this.files){ //support reading files
                for(i = 0; i < this.files.length; i++) {
                    fileArray.push(this.files[i].name);
                }
                if(s.onSelect(this.files) === false) return;
            } else {
                var filenameStr = $(this).val();
                var flist = [];
                fileArray.push(filenameStr);
                if(!isFileTypeAllowed(s, filenameStr)) {
                    s.errMsg = "<b>" + filenameStr + "</b> " + s.extErrorStr + s.allowedTypes;
                    return;
                }
                //fallback for browser without FileAPI
                flist.push({
                    name: filenameStr,
                    size: 'NA'
                });
                if(s.onSelect(flist) === false) return;

            }
            updateFileCounter(s);

            uploadLabel.unbind("click");
            form.hide();
            createCustomInputFile(obj, group, s, uploadLabel);
            form.addClass(group);
            if(!state.iframe && feature.fileapi && feature.formdata){ //HTML5 upload
                form.removeClass(group); //Stop Submitting when.
                var files = this.files;
                form.remove();
                serializeAndUploadFiles(s, obj, files);
            } else {
                var fileList = "";
                for(var i = 0; i < fileArray.length; i++) {
                    if(s.showFileCounter) fileList += scope.fileCounter + s.fileCounterStyle + fileArray[i] + "<br>";
                    else fileList += fileArray[i] + "<br>";;
                    scope.fileCounter++;
                }
                if(s.maxFileCount != -1 && (scope.selectedFiles + fileArray.length) > s.maxFileCount) {
                    s.errMsg = "<b>" + fileList + "</b> " + s.maxFileCountErrorStr + s.maxFileCount;
                    return;
                }
                scope.selectedFiles += fileArray.length;

                var info = createFileInfo(fileList);
                ajaxFormSubmit(form, s, info, fileArray, obj, null); //不预览
            }
        });

        if(s.nestedForms) {
            form.css({
                'margin': 0,
                'padding': 0
            });
            roles.uploadLabel.css({
                position: 'relative',
                overflow: 'hidden',
                cursor: 'default'
            });
            fileInput.css({
                position: 'absolute',
                'cursor': 'pointer',
                'top': '0px',
                'width': '100%',
                'height': '100%',
                'left': '0px',
                'z-index': '100',
                'opacity': '0'
            });
            form.appendTo(uploadLabel);
        } else {
            form.appendTo(document.body);
            form.css({
                margin: 0,
                padding: 0,
                display: 'block',
                position: 'absolute',
                left: '-250px'
            });
            uploadLabel.bind("click", function () {
                fileInput.trigger('click');
            });
        }
    }
    function removeFile(info){
        removeExistingFileName(info);
        var idx = scope.fileInfos.indexOf(info);
        if(idx > -1) scope.fileInfos.splice(idx, 1);
    }
    scope.cancel = function (info) {
        mainQ.splice(mainQ.indexOf(form), 1);
        removeFile(info);
        scope.$emit('cancel', info);
        scope.selectedFiles --; //reduce selected File count
        updateFileCounter(state);
    }
    scope.abort = function (info) {
        removeExistingFileName(info);
        info.abort();
        scope.selectedFiles --; //reduce selected File count
        scope.$emit('abort', info);
    };
    scope.del = function (info) {
        removeFile(info);
        scope.$emit('delete', info);
        scope.selectedFiles --; //reduce selected File count
        updateFileCounter(state);
    };
    scope.download = function(info) {
        window.open(info.url);
    };

    function ajaxFormSubmit(form, s, info, fileArray, obj, file) {
        var currentXHR = null;
        var options = {
            cache: false,
            processData: false,
            forceSync: false,
            type: s.method,
            iframe: s.iframe,
            data: s.formData,
            formData: s.fileData,
            dataType: s.returnType,
            beforeSubmit: function (formData, $form, options) {
                if(s.onSubmit.call(this, fileArray) != false) {
                    if(s.dynamicFormData){
                        var sData = serializeData(s.dynamicFormData());
                        if(sData) {
                            for(var j = 0; j < sData.length; j++) {
                                if(sData[j]) {
                                    if(s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]);
                                    else options.data[sData[j][0]] = sData[j][1];
                                }
                            }
                        }
                    }
                    return true;
                }
                info.uploading = true;
                form.remove();
                scope.$refresh();
                return false;
            },
            beforeSend: function (xhr, o) {
                info.uploading = true;
                if(!feature.formdata){ //For iframe based push
                    info.progress = 5;
                } else info.progress = 1; //Fix for small files
                scope.$refresh();
            },
            uploadProgress: function (event, position, total, percentComplete) {
                if(percentComplete > 98) percentComplete = 98;
                info.progress = percentComplete;
                scope.$refresh();
            },
            success: function (data, message) {
                progressQ.pop();
                info.uploading = false;
                info.url = data.ourl;
                if(s.returnType == "json" && typeof data == "object" && data.hasOwnProperty(s.customErrorKeyStr)) {
                    var msg = data[s.customErrorKeyStr];
                    scope.$emit('error', {status: 200, msg: msg});
                    info.progress = 0;
                    if(s.showStatusAfterError) {
                        info.errMsg = msg;
                    }
                    scope.selectedFiles -= fileArray.length;
                    form.remove();
                    return;
                }
                scope.responses.push(data);
                info.progress = 100;
                scope.$emit('success', info, data);
                form.remove();
                scope.$refresh();
            },
            error: function (xhr, status, errMsg) {
                progressQ.pop();
                info.uploading = false;
                if(xhr.statusText == "abort"){
                    removeFile(info);
                    updateFileCounter(s);
                } else {
                    scope.$emit('error', {status: status, msg: errMsg});
                    info.errMsg = "ERROR: " + errMsg
                    scope.selectedFiles -= fileArray.length;
                }

                form.remove();
                scope.$refresh();
            }
        };

        if(s.showPreview && file != null) {
            if(file.type.toLowerCase().split("/").shift() == "image"){
                getSrcToPreview(file, info);
            }
        }

        if(s.autoSubmit) {
	        form.ajaxForm(options);
            mainQ.push(form);
            submitPendingUploads();
        } else {
	        form.ajaxForm(options);
        }
    }
    scope.init = function(widget){
        roles = widget.roles;
        widget.ready(function(){
            createCustomInputFile(roles.container, formGroup, state, roles.uploadLabel);
        });
    }

});
